Skip to content

Emit pre-expansion feature gate warnings for negative impls and specialization#154527

Open
fmease wants to merge 5 commits intorust-lang:mainfrom
fmease:more-soft-gates
Open

Emit pre-expansion feature gate warnings for negative impls and specialization#154527
fmease wants to merge 5 commits intorust-lang:mainfrom
fmease:more-soft-gates

Conversation

@fmease
Copy link
Copy Markdown
Member

@fmease fmease commented Mar 29, 2026

View all comments

Follow up to #154475; part of #154045.

This shouldn't need any extra input from T-compiler or T-lang since it's legitimized by MCP 535.

However, I have a feeling that negative impls & specialization behind "#[cfg(feature = "nightly")]" are more prevalent in the ecosystem compared to e.g., auto traits & box patterns, so these new warnings will probably hit a bunch of users. In any case, it's only a warning for now not an error so e.g., running crater "in deny mode" or nominating for a T-lang meeting discussion would be disproportionate (esp. since T-lang has confirmed in the past that this is a T-compiler matter).

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Mar 29, 2026
@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Mar 29, 2026

r? @nnethercote

rustbot has assigned @nnethercote.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: compiler
  • compiler expanded to 69 candidates
  • Random selection from 12 candidates

@fmease fmease changed the title Emit a pre-expansion feature gate warning for negative impls and specialization Emit pre-expansion feature gate warnings for negative impls and specialization Mar 29, 2026
&self,
negative_impls,
span.to(of_trait.trait_ref.path.span),
"negative trait bounds are not fully implemented; \
Copy link
Copy Markdown
Member Author

@fmease fmease Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

negative impls != negative trait bounds (the Trait in impl Trait for () is not a trait bound, it's a trait ref)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already covered by tests/ui/traits/negative-impls/feature-gate-negative_impls.rs. Likely a remnant of the time when negative impls and auto traits were part of the same feature, optin_builtin_traits.

//~^ ERROR auto traits are experimental and possibly buggy

impl !AutoDummyTrait for DummyStruct {}
//~^ ERROR negative trait bounds are not fully implemented; use marker types for now
Copy link
Copy Markdown
Member Author

@fmease fmease Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A gate test for negative impls doesn't belong in a gate test file for auto traits. Likely a remnant of the time when negative impls and auto traits were part of the same feature, optin_builtin_traits.

Comment on lines +252 to +255
if let Defaultness::Default(span) = defaultness {
self.psess.gated_spans.gate(sym::min_specialization, span);
self.psess.gated_spans.ungate_last(sym::specialization, span);
}
Copy link
Copy Markdown
Member Author

@fmease fmease Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea is: Enabling feat specialization should imply min_specialization (the latter only supports the specialization of associated functions, not associated constants & types however). That's how the post-expansion feature gate already works (it visits the AST).

For the soft pre-expansion feature gate we basically want the same thing. However, I don't want to pass a param to the item parser that tells it if the item is meant to be free, associated or foreign. Instead, all 3 fn item kinds are now part of min_specialization from a pre-expansion perspective if they're marked default which is absolutely fine (default on free & foreign items gets rejected later on during AST validation).

We ungate specialization here since later in rustc_ast_passes::feature_gate, a span gated behind specialization requires feature(specialization) … which is undesirable for assoc fns ofc. Finally, in AST passes we allow feature(specialization) to unlock spans gated behind specialization and ones behind min_specialization. This leads to the desired semantics.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like some/all of this information should be a comment in the code?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

Copy link
Copy Markdown
Contributor

@nnethercote nnethercote left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems ok, though this stuff is way outside my wheelhouse and I wonder if someone who knows more about it should give a second review. I've given a few minor comments. The third commit is quite hard to review because there are things being moved around and also more substantive changes.

View changes since this review

= help: add `#![feature(auto_traits)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error[E0658]: negative trait bounds are not fully implemented; use marker types for now
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the marker types suggestion no longer true? That seems like useful information.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Readded as proper diagnostic note

// For historical reasons, negative impls don't have a proper pre-expansion feature gate.
// We're now at least issuing a *warning* for those that only exist before macro expansion.
// FIXME(#154045): Turn their post-expansion feature gate into a proper pre-expansion one.
// As part of this, move these test cases into `feature-gate-negative_impls.rs`.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment confused me. Isn't this PR all about adding a proper pre-expansion feature gate? I guess it's not "proper" yet? I don't understand the difference.

Copy link
Copy Markdown
Member Author

@fmease fmease Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not "proper" yet as it's merely a warning for now (as backed by the MCP). Upgrading it to a hard error is the next step at some point in the future that's gonna be much harder to do (crater, fixing fallout downstream, T-lang nomination).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you change "proper pre-expansion one" to "a pre-expansion hard error", or similar?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment on lines +252 to +255
if let Defaultness::Default(span) = defaultness {
self.psess.gated_spans.gate(sym::min_specialization, span);
self.psess.gated_spans.ungate_last(sym::specialization, span);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like some/all of this information should be a comment in the code?

/// The common case.
macro_rules! gate {
($visitor:expr, $feature:ident, $span:expr, $explain:expr) => {{
($visitor:expr, $feature:ident, $span:expr, $explain:expr$(, $help:expr)?) => {{
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand the motivation, but I think a space before the $(, is much more common and better for readability -- it took me a minute to work out what was going on here.

Same on similar cases below.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@nnethercote nnethercote added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Mar 30, 2026
@rust-bors

This comment has been minimized.

@fmease fmease force-pushed the more-soft-gates branch from 8ba153b to d5fc4a2 Compare April 1, 2026 13:33
@fmease fmease mentioned this pull request Apr 1, 2026
@fmease fmease force-pushed the more-soft-gates branch from d5fc4a2 to 1a10297 Compare April 1, 2026 14:43
@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Apr 1, 2026

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@fmease
Copy link
Copy Markdown
Member Author

fmease commented Apr 1, 2026

The third commit is quite hard to review because there are things being moved around and also more substantive changes.

It's probably too late but I've now split that commit and also rearranged the resulting commits.

@rustbot review

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Apr 1, 2026
@fmease fmease force-pushed the more-soft-gates branch from 1a10297 to 5baf12a Compare April 1, 2026 14:49
@rust-log-analyzer

This comment has been minimized.

fmease added 5 commits April 1, 2026 17:01
* utilize Kleene `?` two avoid having two macro matchers with almost
  identical body
* inline `gate_legacy` since it only has one use and since it shouldn't
  be used anywhere else anyway
* remove unnecessary explicit borrows of the visitor
* replace `if let Some(spans) = spans.get(…) { for span in …` with
  `for &span in spans.get(…).into_iter().flatten()` to avoid rightward
  drift and explicit dereferences
* rename `gate_all_legacy…` to `soft_gate_all_legacy…` since it's not a
  "proper" gate that issues an error but merely one that emits a warning
@fmease fmease force-pushed the more-soft-gates branch from 5baf12a to 3e658d3 Compare April 1, 2026 15:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants